﻿namespace Chameleon.Collections
{
	using System;
	using System.Linq;
	using System.Collections;
	using System.Collections.Generic;
	using System.Linq.Expressions;

	/// <summary>
	/// Notifies clients when items are enumerated from a queryable collections.
	/// </summary>
	/// <typeparam name="T">Type of objects the query will return.</typeparam>
	
	internal sealed class InterceptedQuery<T> : IQueryable<T>
	{
		#region Events

			/// <summary>
			/// Event raised when an item from the query has been enumerated.
			/// </summary>
			
			internal event EventHandler<InterceptedEnumerationEventArgs> Enumerated = delegate {};

		#endregion


		#region Fields

			/// <summary>
			/// Query whose enumerator to intercept.
			/// </summary>
			
			IQueryable<T> Query;

		#endregion


		#region IQueryable
		
			/// <summary>
			/// Returns an enumerator that iterates through the collection.
			/// </summary>
			
			public IEnumerator<T> GetEnumerator()
			{
				return InterceptEnumerator();
			}


			/// <summary>
			/// Returns an enumerator that iterates through the collection.
			/// </summary>

			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}


			/// <summary>
			/// Gets the type of the elements that are returned when the expression tree is executed.
			/// </summary>

			public Type ElementType
			{
				get { return Query.ElementType; }
			}


			/// <summary>
			/// Gets the expression tree associated with the query.
			/// </summary>

			public Expression Expression
			{
				get { return Query.Expression; }
			}


			/// <summary>
			/// Gets the query provider associated with the data source.
			/// </summary>

			public IQueryProvider Provider
			{
				get { return Query.Provider; }
			}

		#endregion


		#region Methods

			/// <summary>
			/// Returns an enumerator for the current query that will intercept items being enumerated.
			/// </summary>
			
			InterceptedEnumerator<T> InterceptEnumerator()
			{
				// create the interceptor and register the event to pass through
				return new InterceptedEnumerator<T>( Query.GetEnumerator(), Enumerated );
			}

		#endregion


		#region Constructors

			/// <summary>
			/// Initializes a new instance to intercept enumerations from the specified query.
			/// </summary>
			/// <param name="query">Query whose enumerations to intercept.</param>
			
			internal InterceptedQuery( IQueryable<T> query )
			{
				Query = query;
			}

		#endregion
	}
}
